-module(ham_group).
-author("hpj").

-import(proplists, [get_value/2, get_value/3]).


-include("mysql.hrl").

-include("emqttd.hrl").

-include("emqttd_topic.hrl").

-include("emqttd_packet.hrl").

%% API
-export([handle/1]).

-define( GROUP_DELETE_HAM,      10).
-define( GROUP_CREATE_HAM,      11).
-define( GROUP_ADD_USER,        12).
-define( GROUP_DELETE_USER,     13).

%% register user
handle(Params) ->
  ActionType = get_value(<<"action_type">>,Params),
  handle(ActionType,Params).

%% create group
handle(1, Data) ->
    Groupname = unicode:characters_to_list(get_value(<<"group_name">>,Data)),
    Userid = get_value(<<"send_uid">>,Data),
    Userlist = get_value(<<"uid_list">>,Data,""),
    Topic = tools:get_appkey(),
    {Count,NoneUserJson} = 
      lists:foldl(fun(User,{Acc,Acc1}) ->
        case {mnesia_tools:dirty_read(users,User),User} of
            {[],<<>>} ->
              {Acc,Acc1};
            {[],_} ->
              {Acc+1,[[{<<"userid">>,User}]]++Acc1};
            {_,_}  ->
              {Acc,Acc1}
        end
    end,{0,[]},Userlist++[Userid]),
    case Count > 0 of
      true ->
        {ok, [{<<"code">>,2},{<<"message">>,<<"creategroup fail cause by some user none exist">>},{<<"uid_list">>,NoneUserJson}]};
      false ->
        GroupRecord = #mysql_group{topic = Topic,group_name = Groupname,createtime = 'now()',create_id = Userid},
        case mysql_utils:insert(?IM_POOL,group,GroupRecord,?record_field(mysql_group)) of
          {error,_,_Msg} ->
            {error, [{<<"code">>,5}]};
          _ ->
            Userlist1 = [Userid] ++ Userlist,
            Fun = fun() ->
              TopicRecord = #topic{topic = Topic},
              mnesia:write(topic, TopicRecord, write),
              lists:map(fun(Key) ->
                case Key of 
                  <<>> ->
                    Key;
                  _ ->  
                    Topic_subscriberID = {Topic,Key},
                    SubscriberRecord = #topic_subscriber{id =Topic_subscriberID,topic = Topic,qos = 1,user_id = tools:to_bitstring(Key)},
                    mnesia:write(topic_subscriber, SubscriberRecord, write),
                    Key
                end 
              end, Userlist1)
            end,
            case mnesia:activity(sync_transaction, Fun, [], mnesia_frag) of
              {'exist',_} ->
                {error, [{<<"code">>,5}]};
              _ ->
                {ok, [{<<"code">>,0},{<<"group_id">>,Topic}]}
            end
        end
   end;

%% delete group
handle(2, Data) ->
    Topic = tools:to_bitstring(get_value(<<"group_id">>,Data)),
    Userid = tools:to_bitstring(get_value(<<"send_uid">>,Data)),
    case mysql_utils:select(?IM_POOL,group,mysql_group,?record_field(mysql_group),[{topic,"=",Topic,"and"},{create_id,"=",Userid}],[]) of
        [] ->
          {error, [{<<"code">>,6},{<<"message">>,<<"Insufficient permissions">>}]};
        {error,_,_Msg} ->
          {error, [{<<"code">>,5}]};
        _ ->
            case mnesia:dirty_match_object(topic_subscriber,#topic_subscriber{topic = Topic,_ = '_'}) of
              {'exist',_} ->
                {error, [{<<"code">>,5}]};
              [] ->
                {ok, [{<<"code">>,5},{<<"message">>,<<"group none exist">>}]};
              Subscribers ->
                mysql_utils:delete(?IM_POOL,group,[{topic,"=",Topic,"and"},{create_id,"=",Userid}]),
                mnesia_tools:dirty_delete_object_list(Subscribers),
                {ok, [{<<"code">>,0}]}
            end
    end;
        

%% get group list
handle(3, Data) ->
    Userid =  tools:to_bitstring(get_value(<<"send_uid">>,Data)),
    case mnesia_tools:dirty_index_read(topic_subscriber,Userid,#topic_subscriber.user_id) of
      {'exist',_} ->
          {error, [{<<"code">>,5}]};
      List ->
          Json = lists:foldl(fun(Topic_subscriber,Acc) ->
              case mysql_utils:select(?IM_POOL,group,"group_name,createtime",[{topic,"=",Topic_subscriber#topic_subscriber.topic}],[]) of
                  [] ->
                    Acc;
                  [[Group_name,CreateTime]] ->
                    [[{<<"group_id">>,Topic_subscriber#topic_subscriber.topic},{<<"group_name">>,Group_name}
                      ,{<<"create_time">>,tools:to_js_date(CreateTime)}]] ++ Acc
              end
          end, [], List),
          {ok, [{<<"code">>,0},{<<"group_list">>,lists:reverse(Json)}]}
    end;

%% add user into group
handle(4, Data) ->
    Userlist = get_value(<<"uid_list">>,Data),
    Topic = tools:to_bitstring(get_value(<<"group_id">>,Data)),
    case mysql_utils:select(?IM_POOL,group,mysql_group,?record_field(mysql_group),[{topic,"=",Topic}]) of 
        [] ->
          {error, [{<<"code">>,2},{<<"message">>,<<"group none exist">>}]};
        _  ->
          {Count,NoneUserJson} = lists:foldl(fun(User,{Acc,Acc1}) ->
            case mnesia_tools:dirty_read(users,User) of
              [] ->
                {Acc+1,[[{<<"userid">>,User}]]++Acc1};
              [Userinfo]  ->
                {Acc,[[{<<"userid">>,User},{<<"nickname">>,Userinfo#users.name},{<<"username">>,Userinfo#users.username}]] ++Acc1}
            end
          end,{0,[]},Userlist),
          case Count > 0 of
              true ->
                {error, [{<<"code">>,2},{<<"message">>,<<"add group member fail cause by some user none exist">>},{<<"user">>,NoneUserJson}]};
              false ->
                RecordList = lists:foldl(fun(Userid,Acc) ->
                  ID = {Topic,Userid},
                  case mnesia:dirty_match_object(topic_subscriber,{topic_subscriber,'_',Topic ,'_',Userid}) of
                    [] ->
                      Record = #topic_subscriber{id = ID,topic = Topic,qos = 1,user_id = Userid},
                      Acc ++ [Record];
                    _ ->
                      Acc
                  end
                end,[],Userlist),
                case mnesia_tools:write_list(topic_subscriber, RecordList)  of
                  {'exist',_} ->
                    {error, [{<<"code">>,5}]};
                  _ ->
                    {ok, [{<<"code">>,0}]}
                end
          end
    end;




%% kick user out of the group
handle(5, Data) ->
    Userid = tools:to_bitstring(get_value(<<"send_uid">>,Data)),
    Userlist = get_value(<<"uid_list">>,Data),
    Topic = tools:to_bitstring(get_value(<<"group_id">>,Data)),
   {IDList,UserJson,Count} = lists:foldl(fun(Other_userid,{Acc,Acc1,Acc2}) ->
      case mnesia_tools:dirty_read(users,Other_userid) of
        [] ->
          {Acc+1,[[{<<"userid">>,Other_userid}]]++Acc1,Acc2};
        [Userinfo]  ->
          ID = {Topic,tools:to_bitstring(Other_userid)},
          {Acc ++ [ID],[[{<<"userid">>,Other_userid},{<<"nickname">>,Userinfo#users.name},{<<"username">>,Userinfo#users.username}]] ++Acc1,Acc2}
      end
    end,{[],[],0},Userlist),
    case Count > 0 of
      true ->
        {error,[{<<"code">>,2},{<<"message">>,<<"delete group member fail cause by some user none exist">>},{<<"userlist">>,UserJson}]};
      false ->
        case mysql_utils:select(?IM_POOL,group,mysql_group,?record_field(mysql_group),[{topic,"=",Topic,"and"},{create_id,"=",Userid}],[]) of
          [] ->
            {error, [{<<"code">>,6}]};
          {error,_,_Msg} ->
            {error, [{<<"code">>,5}]};
          _ ->
            case mnesia_tools:delete_list(topic_subscriber,IDList) of
              {'exist',_} ->
                {error, [{<<"ret">>,5}]};
              _ ->
                {ok, [{<<"code">>,0}]}
            end
        end
    end;


%% get userlist from group
handle(6, Data) ->
    Userid = get_value(<<"send_uid">>,Data),
    Topic = get_value(<<"group_id">>,Data),
    case  mnesia_tools:dirty_read(users,Userid) of
        [] ->
          {error, [{<<"code">>,2},{<<"message">>,<<"user none exist">>}]};
        _ ->
          case mnesia_tools:dirty_read(topic_subscriber,{Topic,Userid}) of
              [] ->
                {error, [{<<"code">>,2},{<<"message">>,<<"user none exist this group">>}]};
              _ ->
                RecordList = mnesia_tools:dirty_index_read(topic_subscriber,Topic,#topic_subscriber.topic),
                {Users,Count} = lists:foldl(fun(Record,{Acc,Acc1}) ->
                     case Userid =/= Record#topic_subscriber.user_id of
                       true ->
                         {[Record#topic_subscriber.user_id] ++ Acc,Acc1};
                       false ->
                         {Acc,Acc1+1}
                     end
                end,{[],0},RecordList),
                case Count > 0 of
                  true ->
                    {ok, [{<<"code">>,0},{<<"uid_list">>,lists:sort(Users)}]};
                  false ->
                    {error, [{<<"code">>,2},{<<"message">>,<<"user not belong to this group">>}]}
                end
          end
    end;

% ----------------------------------------------------------------------------------
% 删除群组
% ----------------------------------------------------------------------------------
handle( ?GROUP_DELETE_HAM, Data) ->
    SendUid = get_value(<<"send_uid">>,Data),
    Topic = get_value(<<"group_id">>,Data),
    case  mnesia_tools:dirty_read( users, SendUid ) of
        [] ->
          {error, [{<<"code">>,2},{<<"message">>,<<"user none exist">>}]};
        _ ->
           case mnesia:dirty_match_object(topic_subscriber, #topic_subscriber{topic = Topic,_ = '_'}) of
              {'exist',_} ->
                {error, [{<<"code">>,5}]};
              [] ->
                {ok, [{<<"code">>,5},{<<"message">>,<<"group none exist">>}]};
              Subscribers ->
                mysql_utils:delete(?IM_POOL,group,[{topic,"=",Topic,"and"},{create_id,"=", SendUid}]),
                mnesia:dirty_delete( topic, Topic ),
                mnesia_tools:dirty_delete_object_list(Subscribers),
                {ok, [{<<"code">>,0}]}
            end
    end;

% ----------------------------------------------------------------------------------
% 创建群组
% ----------------------------------------------------------------------------------
handle(?GROUP_CREATE_HAM, Data) ->
    Groupname = unicode:characters_to_list(get_value(<<"group_name">>,Data)),
    Userid = get_value(<<"send_uid">>,Data),
    Userlist0 = get_value(<<"username_list">>,Data, []),
    Userlist = do_get_all_uid_list( Userlist0 ),
    Topic = get_value(<<"group_name">>, Data),

    {Count,NoneUserJson} = 
        lists:foldl(fun(User,{Acc,Acc1}) ->
            case {mnesia_tools:dirty_read(users,User),User} of
                {[],<<>>} ->
                    {Acc,Acc1};
                {[],_} ->
                    {Acc+1,[[{<<"userid">>,User}]]++Acc1};
                {_,_}  ->
                    {Acc,Acc1}
            end
        end,{0,[]},Userlist++[Userid]),

    case Count > 0 of
        true ->
            {ok, [{<<"code">>,2},{<<"message">>,<<"creategroup fail cause by some user none exist">>},{<<"uid_list">>,NoneUserJson}]};
        false ->


        % -----------------------------------------------------------------------
        %       先判断数据库中是否有数据。没有再说
        % -----------------------------------------------------------------------
        case mysql_utils:select(?IM_POOL,group,mysql_group,?record_field(mysql_group),[{topic,"=",Topic}]) of 
            [] ->
                GroupRecord = #mysql_group{topic = Topic,group_name = Groupname,createtime = 'now()',create_id = Userid},
                case mysql_utils:insert(?IM_POOL,group,GroupRecord,?record_field(mysql_group)) of
                    {error,_,_Msg} ->
                        {error, [{<<"code">>,5}]};
                    _ ->
                        do_create_group_write_mnesia(  Userlist, Topic )
                end;
            _OthersErrorOrHaveThisGroup ->
                    {error, [{<<"code">>, 11},{<<"message">>,<<"group exists">>}]}
        end
   end;

handle(?GROUP_ADD_USER , Data) ->
    Userlist0 = get_value(<<"uid_list">>,Data),
    io:format(" UserList0:~p ~n",[  Userlist0 ]),
    Userlist = do_get_all_uid_list( Userlist0 ),
    Topic = tools:to_bitstring(get_value(<<"group_id">>,Data)),
    case mysql_utils:select(?IM_POOL,group,mysql_group,?record_field(mysql_group),[{topic,"=",Topic}]) of 
        [] ->
          {error, [{<<"code">>,2},{<<"message">>,<<"group none exist">>}]};
        _  ->
            
            FunRL = fun(Userid,Acc) ->
                        ID = {Topic,Userid},
                        case mnesia:dirty_match_object(topic_subscriber,{topic_subscriber,'_',Topic ,'_',Userid}) of
                            [] ->
                                Record = #topic_subscriber{id = ID,topic = Topic,qos = 1,user_id = Userid},
                                Acc ++ [Record];
                            _ ->
                                Acc
                        end
                end,
            RecordList = lists:foldl( FunRL, [], Userlist),
            case mnesia_tools:write_list(topic_subscriber, RecordList)  of
                {'exist',_} ->
                    {error, [{<<"code">>,5}]};
                _ ->
                    {ok, [{<<"code">>,0}]}
            end
    end;

handle( ?GROUP_DELETE_USER, Data) ->
    Userid = tools:to_bitstring(get_value(<<"send_uid">>,Data)),
    Userlist = get_value(<<"uid_list">>,Data),
    Topic = tools:to_bitstring(get_value(<<"group_id">>,Data)),
    util:print("Topic:~p ~n", [ Topic ]),
    IDList = [ { Topic, Uid} || Uid <- do_get_all_uid_list( Userlist ) ],
    
    case mysql_utils:select(?IM_POOL,group,mysql_group,?record_field(mysql_group),[{topic,"=",Topic,"and"},{create_id,"=",Userid}],[]) of
        [] ->
            {error, [{<<"code">>,6}]};
        {error,_,_Msg} ->
            {error, [{<<"code">>,5}]};
        _ ->
            util:print("delete list ~p ~n",[ IDList ]),
            case mnesia_tools:delete_list(topic_subscriber,IDList) of
              {'exist',_} ->
                {error, [{<<"ret">>,5}]};
              _ ->
                {ok, [{<<"code">>,0}]}
            end
    end;



handle(_Method, Req) ->
  Response = jsx:encode([{<<"ret">>,4},{<<"message">>,<<"api invalid">>}]),
  Req:ok({"text/plan",Response}).

do_get_all_uid_list( UserList ) ->
    Fun = fun( Username, AccList) ->
        double_convert: get_real_uid_list( Username ) ++ AccList
    end,
    lists:foldl( Fun, [], UserList ).


do_create_group_write_mnesia( Userlist, Topic ) ->
    Userlist1 = Userlist,
    Fun = fun() ->
        TopicRecord = #topic{topic = Topic},
        mnesia:write(topic, TopicRecord, write),
        
        FunWrite = 
            fun(Key) ->
                case Key of 
                    <<>> ->
                        Key;
                    _ ->  
                        Topic_subscriberID = {Topic,Key},
                        SubscriberRecord = #topic_subscriber{id =Topic_subscriberID,topic = Topic,qos = 1,user_id = tools:to_bitstring(Key)},
                        mnesia:write(topic_subscriber, SubscriberRecord, write),
                        Key
                end % end case key
            end,

        lists:map( FunWrite, Userlist1) end,    

    case mnesia:activity(sync_transaction, Fun, [], mnesia_frag) of
        {'exist', Reason} ->
            lager:error(" create group error ~p ~n", [ Reason]),
            {error, [{<<"code">>,5}]};
        _ ->
            {ok, [{<<"code">>,0},{<<"group_id">>,Topic}]}
    end.     % end case mnesia.
